
#ifndef CHORDPROTOCOL_H_

#define CHORDPROTOCOL_H_

#include <string>

#include "object.h"
#include "common.h"
#include "chordkeyinfo.h"
#include "chordmsg.h"
#include "timer.h"

class ChordNode;
class ChordMsg;
class ChordSearchMsg;
class ChordSearchRespMsg;
class RoutineTimer;
class KeyCheckTimer;

struct MsgItem{
	enum PURPOSE{
		MAINTAINANCE,
		QUERY,
		KEY_TRANSFER
	};
	MsgItem() {}
	MsgItem( ChordMsg* msg, sim_time_t it, PURPOSE p ) : msg_(msg), issue_time_(it), purpose_(p) {}
	MsgItem(const MsgItem& other) { msg_=other.msg_; issue_time_=other.issue_time_; purpose_=other.purpose_; }
	ChordMsg   *msg_;
	sim_time_t  issue_time_;
	PURPOSE     purpose_;
};

typedef std::list<MsgItem> TMsgItemList;

struct FingerItem : public ChordNodeInfo{
	FingerItem() : ChordNodeInfo(), last_update_(invalid_sim_time){}
	FingerItem& operator = ( const ChordNodeInfo& other );
	void ensure(chord_net_id_t net_id);
	sim_time_t last_update_;
	//range
	chord_key_t start_;
	chord_key_t end_;
};
typedef std::vector<FingerItem> TFingerVector;

class ChordProtocol : public Object{
	enum CP_STATUS{
		CP_ILLEGAL,
		CP_JOINING,
		CP_READY,
		CP_MOVED_OUT
	};
	public:
		ChordProtocol( ChordNode *node, chord_net_id_t net_id );
		~ChordProtocol();

		bool join();
		void leave();
		void processMessage( ChordMsg *msg );

		chord_net_id_t getChordNetID() const { return net_id_; }

		bool addKey( ChordKeyInfo *key_info );
		uint32_t getNumberOfKey() const { return number_of_key_; }

		ChordNode*     getSuccessorNode(); 
		void           setSuccessor(node_id_t n_id, chord_node_id_t c_nid);
		void           setSuccessor(ChordNodeInfo& info);
		ChordNodeInfo& getSuccessor();

		ChordNode*  getPredecessorNode(); 
		bool        setPredecessor(node_id_t n_id, chord_node_id_t c_nid); 
		bool        setPredecessor(ChordNodeInfo& info); 
		ChordNodeInfo& getPredecessor();

		ChordNode*  getFingerNode(uint32_t index);
		void        setFinger(node_id_t n_id, chord_node_id_t c_nid, uint32_t index);
		FingerItem& getFinger( uint32_t index ); 

		CP_STATUS   getStatus() const { return status_; }
		void        setStatus(CP_STATUS s) { status_=s; }

		bool        isPreceding( chord_key_t k );
		bool		isSuccessorOf( chord_key_t k);

		bool		isActive() const{
			return ( (getStatus()==CP_JOINING)||(getStatus()==CP_READY) );
		}

		bool	 isMerging() const { return is_merging_; }
		void	 setMerging(bool flag=true) { is_merging_= flag; }
		void	 setOldNetID(chord_net_id_t net_id) { old_net_id_ = net_id; }
		chord_net_id_t getOldNetID() const { return old_net_id_; }

		void        routineJob();
		void		checkKeys();

		void		generateQuery( chord_key_t key );


		//utility methods
		static uint32_t keyToFingerIndex( chord_key_t base, chord_key_t key );
		static void fingerRange( chord_key_t base, uint32_t index, chord_key_t& left, chord_key_t& right );

	protected:
		void processSearchMsg( ChordSearchMsg *msg );
		void processSearchRespMsg( ChordSearchRespMsg *msg );
		void processNotifyMsg( ChordNotifyMsg *msg );
		void processGetMsg( ChordGetMsg *msg );
		void processGetRespMsg( ChordGetRespMsg *msg );


		uint32_t determineFingerTableSize();
		void     addPendingMsg( ChordMsg *msg, MsgItem::PURPOSE p=MsgItem::MAINTAINANCE );
		bool     updateFingerTable( ChordSearchRespMsg *msg );
		uint32_t keyToFingerIndex( chord_key_t key );
		void     notify();
		void     checkDeadFingers();
		void     fixFingers();
		FingerItem& closestPrecedingFinger( chord_key_t key );
		FingerItem& firstValidFinger();
		void     fingerString( std::string& s );
		void     keyString( std::string& s );
		bool	 transferKeyTo( ChordKeyInfo *key_info, ChordNode *dst );
		bool	 transferKeyTo( chord_key_t key, node_id_t dst_id );
		int      searchKey( chord_key_t key, MsgItem::PURPOSE p, bool data=false );//return 0:hit immediately 1:search message sent 2:unreachable
		void	 removeKey( TChordKeyInfoList::iterator pos );
		bool	 hasKey( chord_key_t key );
		void	 unregisterKeys();

		void     setReady();
		void     getKeysFromGod();

		void     onMergeDone();
		void     moveOut( chord_net_id_t net_id );


	protected:
		ChordNode           *node_;
		chord_net_id_t       net_id_;
		FingerItem           predecessor_;
		TFingerVector        fingers_;
		TChordKeyInfoList    key_list_;
		uint32_t			 number_of_key_;
		CP_STATUS            status_;
		//for merge
		bool				 is_merging_;
		chord_net_id_t	     old_net_id_;
		chord_net_id_t		 new_net_id_;

		TMsgItemList         pending_msg_;

		RoutineTimer        *rt_timer_;
		KeyCheckTimer		*key_timer_;

		bool				 notify_;

		bool				 first_node_start_;

		friend class ChordGod;
};

class RoutineTimer : public TimerHandler{
	public:
		RoutineTimer( ChordProtocol *p ) : protocol_(p) {}
		virtual void onTimer( Timer *timer ) {
			protocol_->routineJob();
		}
	protected:
		ChordProtocol *protocol_;
};

class KeyCheckTimer : public TimerHandler{
	public:
		KeyCheckTimer( ChordProtocol *p ) : protocol_(p) {}
		virtual void onTimer( Timer *timer ) {
			protocol_->checkKeys();
		}
	protected:
		ChordProtocol *protocol_;
};

class __MSGITEM__ID_PRED
{
public:
	__MSGITEM__ID_PRED( int msg_id )
		: msg_id_(msg_id) {}
	bool operator () ( const MsgItem& item )
	{
		return ( item.msg_->getMsgID()==msg_id_ ); 
	}
private:
	uint32_t msg_id_;
};

#endif /* CHORDPROTOCOL_H_ */

